package com.sdy.supermarket.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sdy.common.constant.Constants;
import com.sdy.common.model.BizException;
import com.sdy.common.utils.Assert;
import com.sdy.common.utils.MapUtil;
import com.sdy.common.utils.StringUtil;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import com.sdy.supermarket.biz.mapper.*;
import com.sdy.supermarket.biz.model.*;
import com.sdy.supermarket.biz.service.*;
import com.sdy.supermarket.biz.vo.AppIpInterfaceVO;
import com.sdy.supermarket.biz.vo.AppIpUpdateVO;
import com.sdy.supermarket.biz.vo.IpResListVo;
import com.sdy.supermarket.biz.vo.UserResListVo;
import com.sdy.usercenter.api.UserQueryApi;
import com.sdy.usercenter.api.dto.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.*;
import static java.util.stream.Collectors.toList;

/**
 * <p>
 * 自建系统 服务实现类
 * </p>
 *
 * @author zzq
 * @since 2019-08-22
 */
@Slf4j
@Service
public class GsAppServiceImpl extends BaseServiceImpl<GsApp> implements GsAppService {
    @Resource
    private GsAppMapper gsAppMapper;
    @Resource
    private GsAppIpMapper gsAppIpMapper;
    @Autowired
    private GsAppInterfaceService gsAppInterfaceService;
    @Autowired
    private AgInterfaceAuthService agInterfaceAuthService;
    @Autowired
    private GsAppIpApplyService gsAppIpApplyService;
    @Resource
    private GsUserResMapper gsUserResMapper;
    @Resource
    private GsResMapper gsResMapper;
    @Resource
    private GsOrderItemMapper gsOrderItemmapper;
    @Resource
    private GsIpChangeMapper gsIpChangeMapper;
    @Autowired
    private GsOrderAppService orderAppService;
    @Autowired
    private UserQueryApi userQueryApi;


    @Override
    public List<GsApp> listApp(Integer userId) {
        UserDTO user = userQueryApi.getUser(userId);
        List<GsApp> appList = list(
                new LambdaQueryWrapper<GsApp>().eq(GsApp::getDeptId, user.getOwnDeptId())
                        .orderByDesc(GsApp::getDef, GsApp::getId)
        );
        if (!appList.isEmpty()) {
            List<GsAppIp> appIpList = gsAppIpMapper.selectList(
                    new LambdaQueryWrapper<GsAppIp>()
                            .in(GsAppIp::getAppId, appList.stream().map(GsApp::getId).collect(Collectors.toList()))
            );
            Map<Integer, List<GsAppIp>> appIpMap = MapUtil.collectionToMapList(appIpList, GsAppIp::getAppId);
            appList.forEach(app -> {
                app.setAppIpList(appIpMap.getOrDefault(app.getId(), Collections.emptyList()));
            });
        }
        return appList;
    }


    @Override
    public GsApp getApp(Integer id) {
        GsApp app = getById(id);
        if (app != null) {
            List<GsAppIp> appIpList = gsAppIpMapper.selectList(
                    new LambdaQueryWrapper<GsAppIp>()
                            .eq(GsAppIp::getAppId, app.getId())
            );
            appIpList = setAppIpState(appIpList, app.getDeptId());
            app.setAppIpList(appIpList);
        }
        return app;
    }

    /**
     * // 给IP列表设置状态
     * // 显示的IP列表中需要添加IP的状态，以此判断能否变动、三种状态：
     * // 0 - 没有任何限制(没有进行任何操作)
     * // 1 - 只能变动应用(进行过修改绑定应用的操作)
     * // 2 - 什么都不能变动(进行过修改IP地址的操作)
     *
     * @param appIpList
     * @return
     */
    private List<GsAppIp> setAppIpState(List<GsAppIp> appIpList, Integer deptId) {
        // 首先查询该用户所有在进行中的订单
        List<GsAppIpApply> list = gsAppIpApplyService.list(Wrappers.<GsAppIpApply>lambdaQuery().eq(GsAppIpApply::getDeptId, deptId).in(GsAppIpApply::getState, Arrays.asList(2, 3, 4)));
        List<String> ipIdList = list.stream().map(GsAppIpApply::getIpId).collect(Collectors.toList());
        StringBuffer ipId = new StringBuffer();
        ipIdList.forEach(ip -> ipId.append(ip));
        if (!list.isEmpty()) {
            // 根据这些订单存储的ipChange表的ID查询ipChange表
            List<GsIpChange> ipChangeList = gsIpChangeMapper.selectList(Wrappers.<GsIpChange>lambdaQuery().in(GsIpChange::getId, Arrays.asList(new String(ipId).split(","))).isNotNull(GsIpChange::getAimsId));
            for (GsAppIp appIp : appIpList) {
                for (GsIpChange ipChange : ipChangeList) {
                    // 没有任何限制的IP
                    if (appIp.getId().equals(ipChange.getAimsId())) {
                        // 需要进行限制的IP
                        if (!appIp.getIp().equals(ipChange.getIp())) {
                            appIp.setState(2);
                        }
                        if (null == appIp.getResIdList() || !appIp.getResIdList().equals(ipChange.getResIdList())) {
                            appIp.setState(1);
                        }
                    } else {
                        appIp.setState(0);
                    }
                }
            }
        } else {
            appIpList.forEach(appIp -> {
                appIp.setState(0);
            });
        }
        return appIpList;
    }

    @Override
    public List<IpResListVo> listUserRes(Integer userId, Page page, Integer ipId) throws BizException {
        List<IpResListVo> listVos = new ArrayList<>();
        List<String> userResIds = new ArrayList<>();
        if (null != ipId) {
            GsAppIp gsAppIp = gsAppIpMapper.selectOne(Wrappers.<GsAppIp>lambdaQuery().eq(GsAppIp::getId, ipId));
            if (null != gsAppIp.getResIdList() && StringUtil.isNotEmpty(gsAppIp.getResIdList()) && StringUtil.isNotBlank(gsAppIp.getResIdList())) {
                userResIds = Arrays.asList(gsAppIp.getResIdList().split(","));
            }
            //(已关联)通过查询该IP的resIDList获取到已关联的资源
            if (userResIds.size() != 0) {
                List<GsRes> gsRes = gsResMapper.selectList(Wrappers.<GsRes>lambdaQuery().in(GsRes::getId, userResIds));
                gsRes.forEach(res -> {
                    // 添加已关联数据
                    listVos.add(new IpResListVo().setId(res.getId()).setResName(res.getName()).setState(0));
                });
            }
        }
        UserDTO user = userQueryApi.getUser(userId);
        //(未关联)查询到已经申请成功的资源，过滤掉该IP已经绑定的资源
        List<Integer> resId = gsUserResMapper.selectList(Wrappers.<GsUserRes>lambdaQuery().eq(GsUserRes::getDeptId, user.getOwnDeptId())).stream().map(res -> res.getResId()).collect(Collectors.toList());
        if (resId.size() != 0) {
            List<GsRes> gsRes1 = gsResMapper.selectList(Wrappers.<GsRes>lambdaQuery().in(GsRes::getId, resId)
                    .notIn(userResIds.size() != 0, GsRes::getId, userResIds));
            gsRes1.forEach(res -> {
                // 添加未关联数据
                listVos.add(new IpResListVo().setId(res.getId()).setResName(res.getName()).setState(1));
            });
        }
        //(申请中)通过查询该用户还未结束订单，获取到申请中的资源列表
        List<GsOrderItem> orderItemList = gsOrderItemmapper.selectList(Wrappers.<GsOrderItem>lambdaQuery().eq(GsOrderItem::getUserId, userId).isNull(GsOrderItem::getVersionNo)
                .eq(GsOrderItem::getState, 4));
        orderItemList.forEach(item -> {
            listVos.add(new IpResListVo().setId(item.getId()).setResName(item.getResName()).setState(2));
        });
        return listVos;
    }

    @Override
    public void createApp(GsApp gsApp) throws BizException {
        UserDTO user = userQueryApi.getUser(gsApp.getUserId());
        gsApp.setId(null);
        gsApp.setCreateTime(new Date());
        gsApp.setCode(UUID.randomUUID().toString());
        gsApp.setUpdateTime(null).setDeptId(user.getOwnDeptId());
        List<GsAppIp> appIpList = gsApp.getAppIpList();
        ArrayList<GsAppIp> collect = appIpList.stream().collect(
                collectingAndThen(toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getIp()))),
                        ArrayList::new));
        Assert.isTrue(appIpList.size() != collect.size(), "禁止提交重复的IP地址");
        save(gsApp);
        if (gsApp.getAppIpList() != null) {
            gsApp.getAppIpList().forEach(appIp -> {
                appIp.setId(null).setCreateTime(new Date()).setAppId(gsApp.getId());
                gsAppIpMapper.insert(appIp);
            });
        }
    }

    @Override
    public void updateApp(GsApp gsApp, Integer userId) throws BizException {
        gsApp.setCreateTime(null);
        gsApp.setUpdateTime(null);
        gsApp.setCode(null);
//        bindIpInterface(gsApp.getUserId(), gsApp);
        updateById(gsApp);
        // 绑定自建系统的IP
        // 判断当前修改的ip中是否涉及到需求申请单中绑定的ip如果涉及到则不能进行修改操作
        List<GsAppIpApply> orderList = gsAppIpApplyService.list(Wrappers.<GsAppIpApply>lambdaQuery().in(GsAppIpApply::getState, Arrays.asList(2, 3, 4)));
        if (!orderList.isEmpty()) {
            List<String> applyNos = orderList.stream().map(GsAppIpApply::getApplyNo).collect(toList());
            List<GsOrderApp> orderApps = orderAppService.list(Wrappers.<GsOrderApp>lambdaQuery().in(GsOrderApp::getOrderId, applyNos));
            // 筛选出原有的ip,对比申请单绑定的ip列表判断要修改的ip是否绑定了申请单,如果有则不可进行修改
            List<GsAppIp> ips = gsApp.getAppIpList().stream().filter(appip -> appip.getId() != null).collect(toList());
            for (GsOrderApp orderApp : orderApps) {
                for (GsAppIp ip : ips) {
                    Assert.isTrue(orderApp.getIp().contains(ip.getIp()), "当前Ip绑定了资源申请单,不可进行修改操作");
                }
            }
        }
        setAppIpList(gsApp, userId);
    }

    private void setAppIpList(GsApp app, Integer userId) throws BizException {
        List<GsAppIp> appIpList = app.getAppIpList();
        ArrayList<GsAppIp> collect = appIpList.stream().collect(
                collectingAndThen(toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getIp()))),
                        ArrayList::new));
        Assert.isTrue(appIpList.size() != collect.size(), "禁止提交重复的IP地址");
        // 筛选出需要新增的数据
        List<GsAppIp> addAppIpList = appIpList.stream().filter(appIp -> appIp.getId() == null).collect(Collectors.toList());
        // 直接新增没有绑定应用的IP
        List<GsAppIp> newIpList = addAppIpList.stream().filter(add -> StringUtil.isBlank(add.getResIdList()) && StringUtil.isEmpty(add.getResIdList())).collect(Collectors.toList());
        // 给需要新增的应用添加APPid
        newIpList.forEach(ip -> {
            ip.setAppId(app.getId());
        });
        if (!newIpList.isEmpty()) {
            gsAppIpMapper.batchInsert(newIpList);
        }
        // 新增的ip中如果绑定了应用则生成订单
        List<GsAppIp> newOrderIpList = addAppIpList.stream().filter(add -> !StringUtil.isBlank(add.getResIdList()) && !StringUtil.isEmpty(add.getResIdList())).collect(Collectors.toList());
        List<GsIpChange> addOrderIp = new ArrayList<>();
        newOrderIpList.forEach(order -> {
            addOrderIp.add(new GsIpChange().setType(0).setAppId(app.getId()).setIp(order.getIp()).setAimsId(null).setResIdList(order.getResIdList()).setCreateTime(new Date()));
        });
        UserDTO user = userQueryApi.getUser(userId);
        if (!addOrderIp.isEmpty()) {
            createIpOrder(addOrderIp, app.getId(), user.getId(), user.getOwnDeptId(), "生成新增类型IP需求申请单");
        }
        // 筛选出原有的数据
        List<GsAppIp> updateAppIpList = appIpList.stream().filter(appip -> appip.getId() != null).collect(Collectors.toList());
        List<Integer> ipIdList = updateAppIpList.stream().filter(ip -> null != ip.getResIdList() && StringUtil.isNotEmpty(ip.getResIdList()) && StringUtil.isNotBlank(ip.getResIdList())).map(ip -> ip.getId()).collect(Collectors.toList());
        if (!ipIdList.isEmpty()) {
            // 根据ID查询数据库中的数据
            List<GsAppIp> gsAppIps = gsAppIpMapper.selectList(
                    Wrappers.<GsAppIp>lambdaQuery().in(GsAppIp::getId, ipIdList));
            // 对比是否变更了IP地址或者变更了绑定的资源,将需要生成订单的数据取出
            List<GsIpChange> updateIpOrder = new ArrayList<>();
            updateAppIpList.forEach(updateAppIp -> {
                gsAppIps.forEach(appIp -> {
                    if (updateAppIp.getId().equals(appIp.getId())) {
                        boolean ipState = updateAppIp.getIp().equals(appIp.getIp());
                        boolean resIdListState = updateAppIp.getResIdList().equals(appIp.getResIdList());
                        if (!ipState) {
                            updateIpOrder.add(new GsIpChange().setType(0).setAppId(app.getId()).setIp(updateAppIp.getIp()).setAimsId(appIp.getId()).setResIdList(updateAppIp.getResIdList()).setCreateTime(new Date()));
                        }
                        if (!resIdListState) {
                            int i = checkNewResIdAndOldResId(updateAppIp.getResIdList(), appIp.getResIdList());
                            if (i != 0 && ipState) {
                                updateIpOrder.add(new GsIpChange().setType(0).setAppId(app.getId()).setIp(updateAppIp.getIp()).setAimsId(appIp.getId()).setResIdList(updateAppIp.getResIdList()).setCreateTime(new Date()));
                            }
                        }
                    }
                });
            });
            if (!updateIpOrder.isEmpty()) {
                createIpOrder(updateIpOrder, app.getId(), user.getId(), user.getOwnDeptId(), "生成修改类型IP需求申请单");
            }
        } else {
            // 如果都是没有绑定应用的操作，则直接修改即可
            if (!updateAppIpList.isEmpty()) {
                gsAppIpMapper.batchUpdate(updateAppIpList);
            }
        }

    }

    private static int checkNewResIdAndOldResId(String newResIdList, String oldResIdList) {
        // 如果旧数据为空，则代表原来没有绑定应用，现在需要添加应用
        if (null == oldResIdList) {
            return 1;
        }
        // 内容不同但是长度相同，视为更换了绑定应用
        if (newResIdList.length() == oldResIdList.length()) {
            return 1;
        }
        // 如果是增加
        if (newResIdList.length() > oldResIdList.length()) {
            if (newResIdList.startsWith(oldResIdList)) {
                return 1;
            } else {
                return 1;
            }
        }
        // 如果是减少
        if (oldResIdList.startsWith(newResIdList)) {
            return 0;
        } else {
            return 1;
        }
    }

    private void createIpOrder(List<GsIpChange> ipList, Integer appId, Integer userId, Integer deptId, String content) throws BizException {
        int batchInsert = gsIpChangeMapper.batchInsert(ipList);
        StringBuilder ipIdListBuffer = new StringBuilder();
        ipList.forEach(ip -> {
            ipIdListBuffer.append(ip.getId() + ",");
        });
        String applyNo = UUID.randomUUID().toString().replace("-", "");
        GsAppIpApply newApply = new GsAppIpApply().setAppId(appId).setIpId(new String(ipIdListBuffer)).setApplyNo(applyNo).setUserId(userId)
                .setContent(content).setState(2).setCreateTime(new Date()).setIsDone(0).setDeptId(deptId);
        boolean save = gsAppIpApplyService.save(newApply);
        Assert.isTrue(batchInsert == 0 || !save, "生成IP需求申请单时出现错误");
    }

    @Override
    public void removeApp(Integer appId) {
        removeById(appId);
        gsAppIpMapper.delete(new LambdaQueryWrapper<GsAppIp>().eq(GsAppIp::getAppId, appId));
    }

    @Override
    public void queryAppInterface(Integer appId) throws BizException {
        GsApp app = getById(appId);
        Assert.isNull(app, "自建系统不存在");
        gsAppInterfaceService.listByAppId(appId);
    }

    @Override
    public List<AppIpInterfaceVO> listAppIpInterfaceBind(Integer appId, String ip) throws BizException {
        Assert.isBlank(ip, "IP不能为空");
        Assert.isTrue(!Pattern.matches(Constants.REGEX_IPV4, ip), "ip格式错误");
        GsApp app = getById(appId);
        Assert.isNull(app, "自建系统不存在");
        List<AgInterfaceAuth> l = agInterfaceAuthService.list(
                new LambdaQueryWrapper<AgInterfaceAuth>()
                        .eq(AgInterfaceAuth::getAppCode, app.getCode())
                        .eq(AgInterfaceAuth::getIp, ip)
        );
        Map<Integer, AgInterfaceAuth> resAuthMap = MapUtil.collectionToMap(l, AgInterfaceAuth::getResId);
        List<GsAppInterface> allL = gsAppInterfaceService.list(
                new LambdaQueryWrapper<GsAppInterface>()
                        .eq(GsAppInterface::getAppCode, app.getCode())
                        .orderByDesc(GsAppInterface::getId)
        );
        List<AppIpInterfaceVO> voList = new ArrayList<>();
        allL.forEach(item -> {
            AppIpInterfaceVO vo = new AppIpInterfaceVO().setResId(item.getResId())
                    .setResName(item.getResName()).setState(2);
            AgInterfaceAuth existItem = resAuthMap.get(item.getResId());
            if (existItem != null) {
                if (existItem.getState().equals(1)) {
                    vo.setState(2);
                } else {
                    vo.setState(3);
                }
            } else {
                vo.setState(1);
            }
            voList.add(vo);
        });
        return voList;
    }

    @Override
    public void bindIpInterface(Integer userId, GsApp gsApp) {
//        GsApp app = getById(appIpUpdateVO.getAppId());
        for (GsAppIp gsAppIp : gsApp.getAppIpList()) {
//            List<Integer> bindResIdList = gsAppIp.getBindResIdList();
//            List<GsAppInterface> appInterfaceList = gsAppInterfaceService.listByAppId(appIpUpdateVO.getAppId());
//            List<Integer> appInterfaceResIdList = appInterfaceList.stream().map(GsAppInterface::getResId).collect(Collectors.toList());
//            if (bindResIdList != null) {
//                bindResIdList.forEach(resId -> {
//                    if (appInterfaceResIdList.contains(resId)) {
//                        agInterfaceAuthService.save(new AgInterfaceAuth()
//                                .setIp(gsAppIp.getIp())
//                                .setResId(resId)
//                                .setState(0)
//                                .setAppCode(app.getCode())
//                                .setCreateTime(new Date()));
//                    }
//                });
//            }
//            if (unbindResIdList != null) {
//                unbindResIdList.forEach(resId -> {
//                    agInterfaceAuthService.remove(
//                            new LambdaQueryWrapper<AgInterfaceAuth>()
//                                    .eq(AgInterfaceAuth::getResId, resId)
//                                    .eq(AgInterfaceAuth::getAppCode, app.getCode())
//                                    .eq(AgInterfaceAuth::getIp, app.getAppIpList())
//                    );
//                });
//            }
        }
    }
}
